package com.zdya.combatdocuments.util;

import cn.hutool.core.io.FileUtil;
import com.itextpdf.text.*;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.PdfSignatureAppearance.RenderingMode;
import com.itextpdf.text.pdf.security.*;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.List;

@Slf4j
public class PDFSign {

    private static float BORDER = 2.5f;
    private static float WD = 595.3f;
    private static float HD = 841.9f;
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");


    public static void main(String[] args) throws Exception {


//        byte[] pdf = cn.hutool.core.io.FileUtil.readBytes("C:\\Users\\HYZ\\Desktop\\Hello.pdf");
        // 图片
        byte[] seal = FileUtil.readBytes("C:\\Users\\HYZ\\Desktop\\3.png");
        // 证书
        String pfxPath = "C:\\Users\\HYZ\\Desktop\\tx.pfx";

//		byte[] pdf = FileUtil.getContent("C:\\Users\\Administrator\\Desktop\\234e.pdf");
//		String pfxPath = "C:\\Users\\Administrator\\Desktop\\签章系统.pfx";
        String pwd = "123456";
//		byte[] seal = FileUtil.getContent("C:\\Users\\Administrator\\Desktop\\刘书堂.png");

//        String pdf =new String(FileUtil.getContent("C:\\Users\\HYZ\\Desktop\\223.txt"));
        // pdf文件
        String pdf = Base64.getEncoder().encodeToString(FileUtil.readBytes("C:\\Users\\HYZ\\Desktop\\5521(2).pdf"));
        Float w = 119.0f;
        Float h = 119.0f;
        Float pxs = null;
        if (pxs == null) {
            pxs = 0F;
        }
      /*  Float x = f[0] + pxs;// 签章起始位置x
//		Float sx = f[0] - (sw / 2);//签章盖在关键字中间： 与PDFUtil中的float ik = (line.indexOf(key) + (key.length()/2));配合使用
        Float y = f[1] - (w / 2);// 签章起始位置y

        int p = (int) f[2];// request.getSpage();*/
        Float x = 120f;
        Float y = 427f;
        int p = 12;

        System.out.println("********");
        System.out.println(x);
        System.out.println(y);

        BASE64Decoder decoder = new BASE64Decoder();
        byte[] pdfs =decoder.decodeBuffer(pdf);
//        byte[] pdfs = Base64.getDecoder().decode(pdf);


        String location = "养老协议";
        String reason = "养老协议";
        String contact = "养老协议";
        String userName = "hongtaiyang";
        boolean isVTime = false;

        pdfs = signPDF(pdfs, pfxPath, pwd, seal, x, y, w, h, p, location, reason, contact, userName);
        FileUtil.writeBytes(pdfs, "C:\\Users\\HYZ\\Desktop\\234e1.pdf");

    }

    public static byte[] signPDF(byte[] pdf, String pfxPath, String pwd, byte[] seal, Float x, Float y, Float w,
                                  Float h, Integer p, String location, String reason, String contact, String userName)
            throws Exception {

//		byte[] pdf = new BASE64Decoder().decodeBuffer(pdfBase64);
        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = SecurityUtils.readPfxToKeyStore(pfxPath, pwd);
        String alias = (String) ks.aliases().nextElement();
        PrivateKey key = (PrivateKey) ks.getKey(alias, pwd.toCharArray());
        Certificate[] chain = ks.getCertificateChain(alias);

        pdf = PDFSign.signPDF(pdf, seal, key, chain, p, x, y, w, h, location, reason, contact, provider.getName(),
                userName);

        if (pdf != null) {
            return pdf;
        }
        return null;
    }

    /**
     * pdf 签名盖章，如果 page<1 则在最后一页签名盖章
     *
     * @param pdf
     * @param seal
     * @param key
     * @param chain
     * @param page
     * @param startX 起始x
     * @param startY 起始y
     * @param width  宽度
     * @param height 高度
     * @return
     * @throws Exception
     */
    public static byte[] signPDF(byte[] pdf, byte[] seal, PrivateKey key, Certificate[] chain, int page, float startX,
                                 float startY, float width, float height, String location, String reason, String contact, String provider,
                                 String userName) throws Exception {

        byte[] ret = null;
        ByteArrayOutputStream out = null;
        PdfReader reader = null;
        PdfStamper stp = null;
        log.info("签章开始。。。。。。。。。" + pdf.length);
        try {
            out = new ByteArrayOutputStream();
            reader = new PdfReader(pdf);
            Rectangle rl = reader.getPageSize(page);

            float w = rl.getWidth();
            float h = rl.getHeight();
            if (w > h) {
                float t = w;
                w = h;
                h = t;
            }
            width = width / (WD / w);
            height = height / (HD / h);

//			System.out.println("宽宽宽宽宽宽宽宽宽："+rl.getWidth());//3264.0   //595.32
//			System.out.println("高高高高高高高高高："+rl.getHeight());//2448.0	 //841.92

//            AcroFields fields = reader.getAcroFields();
//            int num = fields.getTotalRevisions() + 1;
            stp = PdfStamper.createSignature(reader, out, '\0', null, true);
            PdfSignatureAppearance sap = stp.getSignatureAppearance();
//			sap.setCrypto(key, chain, null, PdfSignatureAppearance.VERISIGN_SIGNED);
            if (page < 1) {
                page = reader.getNumberOfPages();
            }
            Image i1 = Image.getInstance(seal);
            sap.setSignatureGraphic(i1);
//			sap.setSignatureGraphic();
//			sap.setAcro6Layers(true);
            sap.setRenderingMode(RenderingMode.GRAPHIC);
            sap.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
            if (location != null) {
                sap.setLocation(location);
            }
            if (reason != null) {
                sap.setReason(reason);
            }
            if (contact != null) {
                sap.setContact(contact);
            }
//			if (provider != null)
//				sap.setProvider(provider);
            float nsy = startY - BORDER;

            TSAClientBouncyCastle tsaClient = null;
            OcspClient ocspClient = null;



            // 签名有边框
            sap.setVisibleSignature(
                    new Rectangle(startX - BORDER, startY - BORDER, startX + width + BORDER, startY + height + BORDER),
                    page, userName );
            PrivateKeySignature pks = new PrivateKeySignature(key, DigestAlgorithms.SHA1, provider);
            ExternalDigest digest = new BouncyCastleDigest();

            MakeSignature.signDetached(sap, digest, pks, chain, null, ocspClient, tsaClient, 0, MakeSignature.CryptoStandard.CMS);
            /*//MyMakeSignature.signDetached(sap, digest, pks, chain, null, null, null, 0, MakeSignature.CryptoStandard.CMS);
//			stp.getWriter().setCompressionLevel(5);*/
            if (stp != null) {
                stp.close();
            }
            ret = out.toByteArray();
            log.info("签章完成。。。。。。。。。" + ret.length);
        } catch (Throwable e) {
//			e.printStackTrace();
            log.error("异常。。。。。。。。。", e);
            throw e;
        } finally {
            if (out != null) {
                out.close();
            }
            if (reader != null) {
                reader.close();
            }
        }
        return ret;
    }




    /**
     * pdf 签名盖章，如果 page<1 则在最后一页签名盖章
     *
     * @param pdf
     * @param seal
     * @param key
     * @param chain
     * @param page
     * @param startX 起始x
     * @param startY 起始y
     * @param width  宽度
     * @param height 高度
     * @return
     * @throws Exception
     */
    public static byte[] signPDF(byte[] pdf, byte[] seal, PrivateKey key, Certificate[] chain, int page, float startX,
                                 float startY, float width, float height) throws Exception {

        return signPDF(pdf, seal, key, chain, page, startX, startY, width, height, null, null, null, null, null);
    }




    private static void setMarkByPage(PdfContentByte pdfContentByte, String markContent)
            throws DocumentException, IOException {
        // 开始设置水印
        pdfContentByte.beginText();
        // 设置水印透明度
        PdfGState gs = new PdfGState();
        // 设置填充字体不透明度为0.4f
        gs.setFillOpacity(0.1f);
        // 设置水印字体参数及大小 (字体参数，字体编码格式，是否将字体信息嵌入到pdf中（一般不需要嵌入），字体大小)
        pdfContentByte.setFontAndSize(BaseFont.createFont("/com/ttf/simhei.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED), 60);
        // 设置透明度
        pdfContentByte.setGState(gs);
        // 设置水印对齐方式 水印内容 X坐标 Y坐标 旋转角度
        pdfContentByte.showTextAligned(Element.ALIGN_RIGHT, markContent, 500, 430, 45);
        // 设置水印颜色
        pdfContentByte.setColorFill(BaseColor.RED);
        // 结束设置
        pdfContentByte.endText();
        pdfContentByte.stroke();
    }

    public static byte[] addWaterMark(byte[] pdf, String markContent, int page) throws Exception {
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            PdfReader reader = new PdfReader(pdf);
            PdfStamper stamper = new PdfStamper(reader, out);

            if (page < 1) {
                int total = reader.getNumberOfPages();
                for (int i = 1; i <= total; i++) {
                    setMarkByPage(stamper.getUnderContent(i), markContent);
                }
            } else {
                setMarkByPage(stamper.getUnderContent(page), markContent);
            }
            stamper.close();
            return out.toByteArray();
        }
    }

    public static int getPage(byte[] pdf) {
        try {
            PdfReader reader = new PdfReader(pdf); // 源文件
            int r = reader.getNumberOfPages();

            reader.close();
            return r;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }

    /**
     * PDF添加印章图片
     *
     * @param pdf
     * @param seal
     * @param page
     * @param startX
     * @param startY
     * @param width
     * @param height
     * @return
     * @throws Exception
     */
//    public static byte[] PicturePDF(byte[] pdf, byte[] seal, int page, float startX, float startY, float width, float height) throws Exception {
//        byte[] ret = null;
//        ByteOutputStream out = null;
//        PdfReader reader = null;
//        PdfStamper stp = null;
//        try {
//            reader = new PdfReader(pdf);
//            out = new ByteOutputStream();
//            stp = new PdfStamper(reader, out);
//            // 读图片
//            Image image = Image.getInstance(seal);
//            // 获取操作的页面
//            page = reader.getNumberOfPages();
//            PdfContentByte under = stp.getOverContent(page);
//            // 根据域的大小缩放图片
//            image.scaleToFit(startY, width);
//            // 添加图片
//            image.setAbsolutePosition(startX, startY);
//            under.addImage(image);
//
//            if (stp != null) {
//                stp.close();
//                ret = out.getBytes();
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw e;
//        } finally {
//            if (out != null) {
//                out.close();
//            }
//            if (reader != null) {
//                reader.close();
//            }
//        }
//        return ret;
//    }

    public static byte[] PicturePDF(byte[] pdf, byte[] seal, int page, float startX, float startY, float width,
                                    float height) throws Exception {
        byte[] ret = null;
        ByteArrayOutputStream out = null;
        PdfReader reader = null;
        PdfStamper stp = null;
        try {
            reader = new PdfReader(pdf);
            out = new ByteArrayOutputStream();
            stp = new PdfStamper(reader, out);
            // 读图片
            Image image = Image.getInstance(seal);
            // 获取操作的页面
            page = reader.getNumberOfPages();
            PdfContentByte under = stp.getOverContent(page);
            // 根据域的大小缩放图片
            image.scaleToFit(startY, width);
            // 添加图片
            image.setAbsolutePosition(startX, startY);
            under.addImage(image);

            if (stp != null) {
                stp.close();
                ret = out.toByteArray();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (out != null) {
                out.close();
            }
            if (reader != null) {
                reader.close();
            }
        }
        return ret;
    }

    /**
     * 按照pdf比例盖印
     * @param pdf
     * @param seal
     * @param page
     * @param startX
     * @param startY
     * @return
     * @throws Exception
     */
    public static byte[] PicturePDFS(byte[] pdf, byte[] seal, int page, float startX, float startY) throws Exception {
        byte[] ret = null;
        ByteArrayOutputStream out = null;
        try {
            // 读取PDF文件
            PdfReader reader = new PdfReader(pdf);
            out = new ByteArrayOutputStream();
            // 创建新的PDF文件
//            Document document = new Document();
            PdfStamper stamper = new PdfStamper(reader, out);
            // 获取PdfContentByte对象，用于绘制图片和PDF内容
//            page = reader.getNumberOfPages();
            PdfContentByte canvas = stamper.getOverContent(page);
            // 加载图片并绘制到PdfContentByte对象上
            Image image = Image.getInstance(seal);
            float w = reader.getPageSizeWithRotation(page).getWidth();
            float h = reader.getPageSizeWithRotation(page).getHeight();
            float imageWidth = image.getWidth();
            float imageHeight = image.getHeight();
            float scaleFactor = Math.min(w / imageWidth, h / imageHeight);
            imageWidth *= scaleFactor;
            imageHeight *= scaleFactor;
            image.setAbsolutePosition(startX, startY);
            image.scaleAbsolute(imageWidth, imageHeight);
            canvas.addImage(image);
            // 关闭PdfStamper和Document对象
            stamper.close();
            ret = out.toByteArray();
//            document.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ret;
    }

    /**
     * 按照pdf比例盖印
     * @param pdf
     * @return
     * @throws Exception
     */
    public static byte[] PicturePDF(byte[] pdf, List<com.zdya.combatdocuments.entity.Image> images) throws Exception {
        byte[] ret = null;
        ByteArrayOutputStream out = null;
        try {
            // 读取PDF文件
            PdfReader reader = new PdfReader(pdf);
            out = new ByteArrayOutputStream();
            // 创建新的PDF文件
            PdfStamper stamper = new PdfStamper(reader, out);

            for (com.zdya.combatdocuments.entity.Image image: images) {
                String[] split = image.getImage().split("base64,");
                byte[] seal = Base64.getDecoder().decode(split[1]);
                Float x = 0F;// x坐标
                Float y = 0F;// y坐标

                // 获取PdfContentByte对象，用于绘制图片和PDF内容
                PdfContentByte canvas = stamper.getOverContent(image.getPage());
                // 加载图片并绘制到PdfContentByte对象上
                Image textImage = Image.getInstance(seal);
                float w = reader.getPageSizeWithRotation(image.getPage()).getWidth();
                float h = reader.getPageSizeWithRotation(image.getPage()).getHeight();
                float imageWidth = textImage.getWidth();
                float imageHeight = textImage.getHeight();
                float scaleFactor = Math.min(w / imageWidth, h / imageHeight);
                imageWidth *= scaleFactor;
                imageHeight *= scaleFactor;
                textImage.setAbsolutePosition(x, y);
                textImage.scaleAbsolute(imageWidth, imageHeight);
                canvas.addImage(textImage);
            }
            // 关闭PdfStamper和Document对象
            stamper.close();
            ret = out.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ret;
    }

    /**
     * 将image对象 转成 BufferedImage
     *
     * @param image
     * @return
     */
    private BufferedImage toBufferedImage(java.awt.Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }
        image = new ImageIcon(image).getImage();
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        try {
            int transparency = Transparency.OPAQUE;
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(
                    image.getWidth(null), image.getHeight(null), transparency);
        } catch (HeadlessException e) {
            //........
        }

        if (bimage == null) {
            int type = BufferedImage.TYPE_INT_RGB;
            bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        }
        Graphics g = bimage.createGraphics();

        g.drawImage(image, 0, 0, null);
        g.dispose();

        return bimage;

    }
}
